package mylittleinvestigations.Collisions;

import java.io.IOException;
import java.util.ArrayList;
import mylittleinvestigations.CaseInformation.CaseXmlReader;
import mylittleinvestigations.CaseInformation.CaseXmlWriter;
import mylittleinvestigations.PersistentThreads.RenderThread;
import mylittleinvestigations.Vector2;
import org.newdawn.slick.Color;
import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.geom.Polygon;

public class CollidableObject
{
    private ArrayList<Vector2> vertices;
    
    public ArrayList<Vector2> getVertices() { return this.vertices; }
    private void setVertices(ArrayList<Vector2> vertices) { this.vertices = vertices; }

    private ArrayList<Vector2> normals;

    public ArrayList<Vector2> getNormals() { return this.normals; }
    private void setNormals(ArrayList<Vector2> normals) { this.normals = normals; }

    private Vector2 position;

    public Vector2 getPosition() { return this.position; }
    public void setPosition(Vector2 position) { this.position = position; }

    private CollidableObject()
    {
        this.vertices = new ArrayList<Vector2>();
        this.normals = new ArrayList<Vector2>();
    }

    public static CollidableObject CreateTriangle(Vector2 vertex1, Vector2 vertex2, Vector2 vertex3)
    {
        CollidableObject triangle = new CollidableObject();

        triangle.setPosition(vertex1.add(vertex2).add(vertex3).scalarMultiply(1.0 / 3));

        triangle.getVertices().add(vertex1.subtract(triangle.getPosition()));
        triangle.getVertices().add(vertex2.subtract(triangle.getPosition()));
        triangle.getVertices().add(vertex3.subtract(triangle.getPosition()));

        Vector2 normalVector1 = vertex1.subtract(vertex2).normalize();
        Vector2 normalVector2 = vertex2.subtract(vertex3).normalize();
        Vector2 normalVector3 = vertex3.subtract(vertex1).normalize();

        triangle.getNormals().add(normalVector1);
        triangle.getNormals().add(new Vector2(normalVector1.getY(), -normalVector1.getX()));
        triangle.getNormals().add(normalVector2);
        triangle.getNormals().add(new Vector2(normalVector2.getY(), -normalVector2.getX()));
        triangle.getNormals().add(normalVector3);
        triangle.getNormals().add(new Vector2(normalVector3.getY(), -normalVector3.getX()));

        return triangle;
    }

    public static CollidableObject CreateRectangle(Vector2 position, Vector2 size)
    {
        CollidableObject rectangle = new CollidableObject();

        rectangle.setPosition(position.add(size.scalarMultiply(0.5)));

        rectangle.getVertices().add(position.subtract(rectangle.getPosition()));
        rectangle.getVertices().add(new Vector2(position.getX(), position.getY() + size.getY()).subtract(rectangle.getPosition()));
        rectangle.getVertices().add(position.add(size).subtract(rectangle.getPosition()));
        rectangle.getVertices().add(new Vector2(position.getX() + size.getX(), position.getY()).subtract(rectangle.getPosition()));

        rectangle.getNormals().add(new Vector2(1, 0));
        rectangle.getNormals().add(new Vector2(0, 1));

        return rectangle;
    }

    public static CollidableObject CreatePolygon(ArrayList<Vector2> vertexes)
    {
        CollidableObject polygon = new CollidableObject();
        Vector2 position = new Vector2(0, 0);
        
        for (int i = 0; i < vertexes.size(); i++)
        {
            position = position.add(vertexes.get(i));
        }

        polygon.setPosition(position.scalarMultiply(1.0d / vertexes.size()));
        
        for (int i = 0; i < vertexes.size(); i++)
        {
            polygon.getVertices().add(vertexes.get(i).subtract(polygon.getPosition()));
            
            if (i > 0)
            {
                Vector2 edgeVector = vertexes.get(i).subtract(vertexes.get(i - 1));
                polygon.getNormals().add(new Vector2(-edgeVector.getY(), edgeVector.getX()).normalize());
            }
        }
        
        Vector2 edgeVector = vertexes.get(vertexes.size() - 1).subtract(vertexes.get(0));
        polygon.getNormals().add(new Vector2(-edgeVector.getY(), edgeVector.getX()).normalize());

        return polygon;
    }
    
    public void Draw(Vector2 topLeftCornerPosition, GameContainer gc, Graphics g)
    {
        Polygon polygon = new Polygon();
        
        for (int i = 0; i < this.vertices.size(); i++)
        {
            Vector2 vertexPosition = this.vertices.get(i);
            polygon.addPoint(
                    (float)(vertexPosition.getX() + this.position.getX() + topLeftCornerPosition.getX()),
                    (float)(vertexPosition.getY() + this.position.getY() + topLeftCornerPosition.getY()));
        }
        
        RenderThread.getInstance().AddPolygonToRenderQueue(polygon, Color.white);
    }

    void SaveToXml(CaseXmlWriter writer) throws IOException
    {
        writer.StartElement("CollidableObject");
        
        writer.StartElement("Vertices");
        
        for (int i = 0; i < this.vertices.size(); i++)
        {
            writer.StartElement("VertexEntry");
            this.vertices.get(i).SaveToXml(writer);
            writer.EndElement();
        }
        
        writer.EndElement();
        
        writer.StartElement("Normals");
        
        for (int i = 0; i < this.normals.size(); i++)
        {
            writer.StartElement("NormalEntry");
            this.normals.get(i).SaveToXml(writer);
            writer.EndElement();
        }
        
        writer.EndElement();
        
        writer.StartElement("Position");
        
        this.position.SaveToXml(writer);
        
        writer.EndElement();

        writer.EndElement();
    }

    public CollidableObject(CaseXmlReader reader)
    {
        this.vertices = new ArrayList<Vector2>();
        this.normals = new ArrayList<Vector2>();
        
        reader.StartElement("CollidableObject");
        
        reader.StartElement("Vertices");
        reader.StartList("VertexEntry");
        
        while (reader.MoveToNextListItem())
        {
            this.vertices.add(new Vector2(reader));
        }
        
        reader.EndElement();
        
        reader.StartElement("Normals");
        reader.StartList("NormalEntry");
        
        while (reader.MoveToNextListItem())
        {
            this.normals.add(new Vector2(reader));
        }
        
        reader.EndElement();
        
        reader.StartElement("Position");
        this.position = new Vector2(reader);
        reader.EndElement();

        reader.EndElement();
    }
}